﻿using System;
using System.Collections.Generic;
using System.Web;
using Telerik.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Web.UI;
using System.IO;

namespace LenderClearingHouse
{
  /// <summary>
  /// Imports and exports settings from a RadGrid instance.
  /// </summary>
  public class GridSettingsPersister
  {
    /// <summary>
    /// Initializes an instance of GridSettingsPersister from a RadGrid instance
    /// </summary>
    /// <param name="grid">The RadGrid instance to import and exports settings</param>
    public GridSettingsPersister(RadGrid grid)
      : this(grid, GridSettingsType.All)
    {

    }

    /// <summary>
    /// Initializes an instance of GridSettingsPersister from a RadGrid instance
    /// and a collection GridSettingsType values
    /// </summary>
    /// <param name="grid">The RadGrid instance to import and exports settings</param>
    /// <param name="persistedSettings">
    /// A collection of GridSettingType values specifying the type of grid settings
    /// to import or export
    /// </param>
    public GridSettingsPersister(RadGrid grid, GridSettingsType persistedSettingFlags)
    {
      _grid = grid;
      _persistedSettingTypes = persistedSettingFlags;
      _settings = new GridSettingsCollection();
      _settings.ColumnSettings = new List<ColumnSettings>();
      _settings.AutoGeneratedColumnSettings = new List<ColumnSettings>();
    }

    private RadGrid _grid;
    private GridSettingsType _persistedSettingTypes;
    private GridSettingsCollection _settings;

    /// <summary>
    /// The underlyiong RadGrid instance to import or export settings from
    /// </summary>
    public RadGrid Grid
    {
      get { return _grid; }
    }

    /// <summary>
    /// Gets or sets the GridSettingType flags that specify the grid settings to 
    /// export or import
    /// </summary>
    public virtual GridSettingsType PersistedSettingTypes
    {
      get { return _persistedSettingTypes; }
      set { _persistedSettingTypes = value; }
    }

    protected virtual GridSettingsCollection Settings
    {
      get { return _settings; }
      set { _settings = value; }
    }

    /// <summary>
    /// Saves the current grid settings and returns the settings serilized to string
    /// </summary>
    public virtual string SaveSettings()
    {
      return GetSavedSettings().ToString();
    }

    /// <summary>
    /// Saves the current grid settings and retrieves the underlying
    /// GridSettingsCollection instance that contains the grid settings
    /// </summary>
    public virtual GridSettingsCollection GetSavedSettings()
    {
      if (Grid == null)
      {
        throw new NullReferenceException();
      }

      if (IsSettingSpecified(GridSettingsType.Paging)) SavePagingSettings();
      if (IsSettingSpecified(GridSettingsType.Grouping)) SaveGroupByExpressions();
      if (IsSettingSpecified(GridSettingsType.Sorting)) SaveSortExpressions();
      if (IsSettingSpecified(GridSettingsType.Filtering)) SaveFilterExpression();
      if (IsSettingSpecified(GridSettingsType.ColumnSettings)) SaveColumnSettings();

      return Settings;
    }

    protected bool IsSettingSpecified(GridSettingsType settingType)
    {
      return (PersistedSettingTypes & GridSettingsType.All) == GridSettingsType.All ||
             (PersistedSettingTypes & settingType) == settingType;
    }

    protected virtual void SavePagingSettings()
    {
      Settings.PageSize = Grid.MasterTableView.PageSize;
    }

    protected virtual void SaveGroupByExpressions()
    {
      Settings.GroupByExpressionsStates = new object[Grid.MasterTableView.GroupByExpressions.Count];
      for (int i = 0; i < Settings.GroupByExpressionsStates.Length; i++)
      {
        Settings.GroupByExpressionsStates[i] = ((IStateManager)Grid.MasterTableView.GroupByExpressions[i]).SaveViewState();
      }
    }

    protected virtual void SaveSortExpressions()
    {
      Settings.SortExpressionsState = ((IStateManager)Grid.MasterTableView.SortExpressions).SaveViewState();
    }

    protected virtual void SaveFilterExpression()
    {
      Settings.FilterExpression = Grid.MasterTableView.FilterExpression;
    }

    protected virtual void SaveColumnSettings()
    {
      Settings.ColumnSettings.Clear();
      foreach (GridColumn column in Grid.MasterTableView.Columns)
      {
        Settings.ColumnSettings.Add(GetColumnSettings(column));
      }

      Settings.AutoGeneratedColumnSettings.Clear();
      foreach (GridColumn column in Grid.MasterTableView.AutoGeneratedColumns)
      {
        Settings.AutoGeneratedColumnSettings.Add(GetColumnSettings(column));
      }
    }

    private ColumnSettings GetColumnSettings(GridColumn column)
    {
      ColumnSettings colSettings = new ColumnSettings();
      colSettings.UniqueName = column.UniqueName;
      colSettings.Width = column.HeaderStyle.Width;
      colSettings.Visible = column.Visible;
      colSettings.Display = column.Display;
      colSettings.OrderIndex = column.OrderIndex;
      colSettings.CurrentFilterFunction = column.CurrentFilterFunction;
      colSettings.CurrentFilterValue = column.CurrentFilterValue;

      return colSettings;
    }

    private void SetColumnSettings(ref GridColumn column, ColumnSettings setting)
    {
      column.Display = setting.Display;
      column.Visible = setting.Visible;
      column.HeaderStyle.Width = setting.Width;
      column.OrderIndex = setting.OrderIndex;
      column.CurrentFilterFunction = setting.CurrentFilterFunction;
      column.CurrentFilterValue = setting.CurrentFilterValue;
    }

    /// <summary>
    /// Loads grids settings from a serialized string
    /// </summary>
    /// <param name="value">The string that contains the serialized settings</param>
    public virtual void LoadSettings(string value)
    {
      LoadSettings(GridSettingsCollection.LoadFromSerializedData(value));
    }

    /// <summary>
    /// Loads grids settings from a byte array
    /// </summary>
    /// <param name="data">The byte array that contains the serialized grid settings</param>
    public virtual void LoadSettings(byte[] data)
    {
      LoadSettings(GridSettingsCollection.LoadFromSerializedData(data));
    }

    /// <summary>
    /// Loads grid settings from a GridSettingsCollection instance
    /// </summary>
    /// <param name="settings">The GridSettingsCollection instance to load settings from</param>
    public virtual void LoadSettings(GridSettingsCollection settings)
    {
      if (Grid == null || settings == null)
      {
        throw new NullReferenceException();
      }

      Settings = settings;

      if (IsSettingSpecified(GridSettingsType.Paging)) LoadPagingSettings();
      if (IsSettingSpecified(GridSettingsType.Grouping)) LoadGroupByExpressions();
      if (IsSettingSpecified(GridSettingsType.Sorting)) LoadSortExpressions();
      if (IsSettingSpecified(GridSettingsType.Filtering)) LoadFilterExpression();
      if (IsSettingSpecified(GridSettingsType.ColumnSettings)) LoadColumnSettings();
    }

    protected virtual void LoadPagingSettings()
    {
      if (Grid.MasterTableView.AllowPaging && Settings.PageSize > 0)
      {
        Grid.MasterTableView.PageSize = Settings.PageSize;
      }
    }

    protected virtual void LoadGroupByExpressions()
    {
      if (Settings.GroupByExpressionsStates == null) return;

      Grid.MasterTableView.GroupByExpressions.Clear();
      foreach (object expressionState in Settings.GroupByExpressionsStates)
      {
        GridGroupByExpression expression = new GridGroupByExpression();
        ((IStateManager)expression).LoadViewState(expressionState);
        Grid.MasterTableView.GroupByExpressions.Add(expression);
      }
    }

    protected virtual void LoadSortExpressions()
    {
      if (Settings.SortExpressionsState == null) return;

      ((IStateManager)Grid.MasterTableView.SortExpressions).LoadViewState(Settings.SortExpressionsState);
    }

    protected virtual void LoadFilterExpression()
    {
      Grid.MasterTableView.FilterExpression = Settings.FilterExpression;
    }

    protected virtual void LoadColumnSettings()
    {
      if (Settings.AutoGeneratedColumnSettings.Count > 0)
      {
        Grid.ColumnCreated += new GridColumnCreatedEventHandler(Grid_ColumnCreated);
      }

      foreach (ColumnSettings colSetting in Settings.ColumnSettings)
      {
        GridColumn column = Grid.MasterTableView.GetColumnSafe(colSetting.UniqueName);

        if (column != null)
        {
          SetColumnSettings(ref column, colSetting);
        }
      }
    }

    private void Grid_ColumnCreated(object sender, GridColumnCreatedEventArgs e)
    {
      ColumnSettings settings = Settings.AutoGeneratedColumnSettings.Find(delegate(ColumnSettings set)
      {
        return set.UniqueName == e.Column.UniqueName;
      });
      GridColumn column = e.Column;

      if (settings != null)
      {
        SetColumnSettings(ref column, settings);
      }
    }
  }

  /// <summary>
  /// Enumerates the types of grid settings that can be persisted
  /// </summary>
  [Flags]
  public enum GridSettingsType
  {
    Paging = 1,
    Sorting = 2,
    Filtering = 4,
    Grouping = 8,
    ColumnSettings = 16,
    All = 32
  }

  /// <summary>
  /// Represents a collection of grid settings
  /// </summary>
  [Serializable]
  public class GridSettingsCollection
  {
    private int _pageSize;
    private object[] _groupByExpressionsStates;
    private object _sortExpressionsState;
    private string _filterExpression;
    private List<ColumnSettings> _columnSettings;
    private List<ColumnSettings> _autoColumnSettings;

    public int PageSize
    {
      get { return _pageSize; }
      set { _pageSize = value; }
    }

    public object[] GroupByExpressionsStates
    {
      get { return _groupByExpressionsStates; }
      set { _groupByExpressionsStates = value; }
    }

    public object SortExpressionsState
    {
      get { return _sortExpressionsState; }
      set { _sortExpressionsState = value; }
    }

    public string FilterExpression
    {
      get { return _filterExpression; }
      set { _filterExpression = value; }
    }

    public List<ColumnSettings> ColumnSettings
    {
      get { return _columnSettings; }
      set { _columnSettings = value; }
    }

    public List<ColumnSettings> AutoGeneratedColumnSettings
    {
      get { return _autoColumnSettings; }
      set { _autoColumnSettings = value; }
    }

    /// <summary>
    /// Returns the serialized object as string
    /// </summary>
    public override string ToString()
    {
      LosFormatter formatter = new LosFormatter();
      using (StringWriter writer = new StringWriter())
      {
        formatter.Serialize(writer, this);
        return writer.ToString();
      }
    }

    /// <summary>
    /// Returns the serialized object as byte array
    /// </summary>
    public byte[] ToArray()
    {
      LosFormatter formatter = new LosFormatter();
      using (MemoryStream stream = new MemoryStream())
      {
        formatter.Serialize(stream, this);
        return stream.ToArray();
      }
    }

    /// <summary>
    /// Gets the GridSettingsCollectionInstance from its serialized string data
    /// </summary>
    /// <param name="data">The object as serialized string data</param>
    public static GridSettingsCollection LoadFromSerializedData(string data)
    {
      LosFormatter formatter = new LosFormatter();
      return (GridSettingsCollection)formatter.Deserialize(data);
    }

    /// <summary>
    /// Gets the GridSettingsCollectionInstance from its serialized byte array
    /// </summary>
    /// <param name="data">The object as serialized byte array</param>
    public static GridSettingsCollection LoadFromSerializedData(byte[] data)
    {
      LosFormatter formatter = new LosFormatter();
      using (MemoryStream stream = new MemoryStream(data))
      {
        return (GridSettingsCollection)formatter.Deserialize(stream);
      }
    }
  }

  /// <summary>
  /// Represents a collection of grid column settings
  /// </summary>
  [Serializable]
  public class ColumnSettings
  {
    private string _uniqueName;
    private int _orderIndex;
    private Unit _width;
    private bool _visible;
    private bool _display;
    private GridKnownFunction _currentFilterFunction;
    private string _currentFilterValue;

    public string UniqueName
    {
      get { return _uniqueName; }
      set { _uniqueName = value; }
    }

    public int OrderIndex
    {
      get { return _orderIndex; }
      set { _orderIndex = value; }
    }

    public Unit Width
    {
      get { return _width; }
      set { _width = value; }
    }

    public bool Visible
    {
      get { return _visible; }
      set { _visible = value; }
    }

    public bool Display
    {
      get { return _display; }
      set { _display = value; }
    }

    public GridKnownFunction CurrentFilterFunction
    {
      get { return _currentFilterFunction; }
      set { _currentFilterFunction = value; }
    }

    public string CurrentFilterValue
    {
      get { return _currentFilterValue; }
      set { _currentFilterValue = value; }
    }
  }
}